# frozen_string_literal: true

require('all')
require('set')

class BoardTest < Test::Unit::TestCase
  SIMPLE_BOARD = [
    %w[a a g],
    %w[a a -],
    %w[b b -]
  ].freeze

  def test_globals
    assert_equal(
      Game.instance.initial_board,
      Board.new(GAMES[:reference][:initial_board])
    )

    assert_equal(
      Game.instance.final_mask,
      Board.new(GAMES[:reference][:final_mask])
    )
  end

  def test_vide
    assert(
      Board.new(
        [
          %w[- - -],
          %w[- - -],
          %w[- - -]
        ]
      ).vide?
    )

    refute(
      Board.new(
        [
          %w[- - -],
          %w[- - -],
          %w[- - a]
        ]
      ).vide?
    )
  end

  def test_flip_v
    assert_equal(
      Board.new(
        [
          %w[b b -],
          %w[a a -],
          %w[a a g]
        ]
      ),
      Board.new(SIMPLE_BOARD).flip_v
    )

    assert_equal(
      Board.new(SIMPLE_BOARD),
      Board.new(SIMPLE_BOARD).flip_v.flip_v
    )
  end

  def test_flip_h
    assert_equal(
      Board.new(
        [
          %w[g a a],
          %w[- a a],
          %w[- b b]
        ]
      ),
      Board.new(SIMPLE_BOARD).flip_h
    )

    assert_equal(
      Board.new(SIMPLE_BOARD),
      Board.new(SIMPLE_BOARD).flip_h.flip_h
    )
  end

  def test_lift
    Board.new(SIMPLE_BOARD).lift_piece('a').tap do |r|
      assert_equal(
        PieceMask.new(
          [
            %w[a a -],
            %w[a a -],
            %w[- - -]
          ]
        ),
        r[:mask]
      )
      assert_equal(
        Board.new(
          [
            %w[- - g],
            %w[- - -],
            %w[b b -]
          ]
        ),
        r[:board]
      )
    end

    Board.new(SIMPLE_BOARD).lift_piece('c').tap do |r|
      assert(r[:mask].vide?)
      assert_equal(Board.new(SIMPLE_BOARD), r[:board])
    end
  end

  def test_drop
    assert_equal(
      Board.new(
        [
          %w[a a g],
          %w[a a i],
          %w[b b -]
        ]
      ),
      Board.new(SIMPLE_BOARD).drop_piece(
        PieceMask.new(
          [
            %w[- - -],
            %w[- - i],
            %w[- - -]
          ]
        )
      )
    )
    assert_nil(
      Board.new(SIMPLE_BOARD).drop_piece(
        PieceMask.new(
          [
            %w[- b b],
            %w[- - -],
            %w[- - -]
          ]
        )
      )
    )
  end

  def test_move_piece
    assert_equal(
      Board.new(
        [
          %w[- a a],
          %w[- a a],
          %w[b b g]
        ]
      ),
      Board.new(SIMPLE_BOARD)
        .move_piece('b', :right)
        .move_piece('b', :left)
        .move_piece('g', :down)
        .move_piece('g', :up)
        .move_piece('g', :down)
        .move_piece('g', :down)
        .move_piece('a', :right)
    )

    assert_nil(
      Board.new(SIMPLE_BOARD).move_piece('a', :up)
    )
  end

  def test_legal_moves
    assert_equal(
      [
        Move.new(
          Board.new(
            [
              %w[a a -],
              %w[a a g],
              %w[b b -]
            ]
          ),
          'g',
          :down
        ),
        Move.new(
          Board.new(
            [
              %w[a a g],
              %w[a a -],
              %w[- b b]
            ]
          ),
          'b',
          :right
        )
      ].to_set,
      Board.new(SIMPLE_BOARD).legal_moves.to_set
    )
  end

  def test_mask_geometry
    PieceMask.nu(Board.new(SIMPLE_BOARD), 'a').tap do |mask|
      assert_equal(
        [0, 0, 2, 2],
        mask.piece_geometry(true).values_at(:x, :y, :rows, :columns)
      )
    end

    PieceMask.nu(Board.new(SIMPLE_BOARD), 'g').tap do |mask|
      assert_equal(
        [2, 0, 1, 1],
        mask.piece_geometry(true).values_at(:x, :y, :rows, :columns)
      )
    end

    PieceMask.nu(Board.new(SIMPLE_BOARD), 'b').tap do |mask|
      assert_equal(
        [0, 2, 1, 2],
        mask.piece_geometry(true).values_at(:x, :y, :rows, :columns)
      )
    end

    PieceMask.nu(Board.new(SIMPLE_BOARD), 'b').tap do |mask|
      assert_equal(
        [nil, nil, 1, 2],
        mask.piece_geometry.values_at(:x, :y, :rows, :columns)
      )
    end
  end
end
